package com.train.base.service.impl;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.ruoyi.system.service.ISysUserService;
import com.train.base.domain.ExamPlan;
import com.train.base.domain.ExamPlanVenue;
import com.train.base.domain.ExamPlanVenueUser;
import com.train.base.domain.ExamTestPaper;
import com.train.base.domain.ExamTestPaperExtractRule;
import com.train.base.domain.ExamTestPaperModule;
import com.train.base.enums.ExamTestPaperStateEnums;
import com.train.base.enums.PlanStatusEnums;
import com.train.base.enums.PlanTypeEnums;
import com.train.base.enums.WhetherCanResitEnums;
import com.train.base.mapper.ExamPlanMapper;
import com.train.base.service.IExamPlanService;
import com.train.base.service.IExamPlanVenueService;
import com.train.base.service.IExamTestPaperModuleService;
import com.train.base.service.IExamTestPaperService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 考试计划Service业务层处理
 *
 * @author keke
 * @date 2024-03-28
 */
@Service
public class ExamPlanServiceImpl implements IExamPlanService {
    @Autowired
    private ExamPlanMapper examPlanMapper;
    @Autowired
    private IExamPlanVenueService examPlanVenueService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private IExamTestPaperModuleService examTestPaperModuleService;
    @Autowired
    private IExamTestPaperService examTestPaperService;

    /**
     * 查询考试计划
     *
     * @param id 考试计划主键
     * @return 考试计划
     */
    @Override
    public ExamPlan selectExamPlanById(Long id) {
        return examPlanMapper.selectExamPlanById(id);
    }

    /**
     * 查询考试计划列表
     *
     * @param examPlan 考试计划
     * @return 考试计划
     */
    @Override
    public List<ExamPlan> selectExamPlanList(ExamPlan examPlan) {
        List<ExamPlan> examPlans = examPlanMapper.selectExamPlanList(examPlan);
        // 查询考试计划关联的模板
        List<Long> moduleIds = examPlans.stream().map(ExamPlan::getExamTestPaperModuleId).toList();
        Map<Long, String> moduleMap = examTestPaperModuleService.selectExamTestPaperModuleByIds(moduleIds).stream().collect(Collectors.toMap(ExamTestPaperModule::getId, ExamTestPaperModule::getName));
        // 查询考试计划场次
        ExamPlanVenue examPlanVenue = new ExamPlanVenue();
        examPlanVenue.setExamPlanIds(examPlans.stream().map(ExamPlan::getId).toList());
        List<ExamPlanVenue> examPlanVenues = examPlanVenueService.selectExamPlanVenueList(examPlanVenue);
        Map<Long, List<ExamPlanVenue>> examVenuesMap = examPlanVenues.stream().collect(Collectors.groupingBy(ExamPlanVenue::getExamPlanId));
        examPlans.forEach(exam -> {
            if (!ObjectUtils.isEmpty(examVenuesMap.get(exam.getId()))) {
                exam.setExamPlanVenueList(examVenuesMap.get(exam.getId()));
            }
            if(!ObjectUtils.isEmpty(moduleMap.get(exam.getExamTestPaperModuleId()))) {
                exam.setExamTestPaperModuleName(moduleMap.get(exam.getExamTestPaperModuleId()));
            }
        });
        return examPlans;
    }

    /**
     * 新增考试计划
     *
     * @param examPlan 考试计划
     * @return 结果
     */
    @Override
    public int insertExamPlan(ExamPlan examPlan) {
        examPlan.setExamType(PlanTypeEnums.FIXED.getCode());
        examPlan.setWhetherCanResit(WhetherCanResitEnums.NOT_CAN.getCode());
        examPlan.setCreateTime(LocalDateTime.now());
        examPlan.setId(SnowflakeIdWorker.build().nextId());
        examPlan.setStatu(PlanStatusEnums.DRAFT.getCode());
        return examPlanMapper.insertExamPlan(examPlan);
    }

    /**
     * 修改考试计划
     *
     * @param examPlan 考试计划
     * @return 结果
     */
    @Override
    public int updateExamPlan(ExamPlan examPlan) {
        examPlan.setUpdateTime(DateUtils.getNowDate());
        return examPlanMapper.updateExamPlan(examPlan);
    }

    /**
     * 批量删除考试计划
     *
     * @param ids 需要删除的考试计划主键
     * @return 结果
     */
    @Override
    public int deleteExamPlanByIds(Long[] ids) {
        return examPlanMapper.deleteExamPlanByIds(ids);
    }

    /**
     * 删除考试计划信息
     *
     * @param id 考试计划主键
     * @return 结果
     */
    @Override
    public int deleteExamPlanById(Long id) {
        return examPlanMapper.deleteExamPlanById(id);
    }

    @Override
    @Transactional
    public int updateStatus(List<Long> ids, Long status) {
        if(CollectionUtils.isEmpty(ids)){
            return 0;
        }
        if (status.equals(PlanStatusEnums.RELEASE.getCode())) {
            release(ids);
        }
        return examPlanMapper.updateStatus(ids, status);
    }

    @Override
    public List<ExamPlan> selectExamPlanByIds(List<Long> planIds) {
        return examPlanMapper.selectExamPlanByIds(planIds);
    }

    @Override
    public List<ExamPlan> selectNeedCreatePlan() {
        return examPlanMapper.selectNeedCreatePlan();
    }

    /**
     * 计划发布,生成试卷
     *
     * @param ids 计划id
     */
    public void release(List<Long> ids) {
        // 获取要发布的计划
        List<ExamPlan> examPlans = examPlanMapper.selectExamPlanByIds(ids);
        examPlans.forEach(e -> {
            ExamTestPaperModule examTestPaperModules = examTestPaperModuleService.selectExamTestPaperModuleById(e.getExamTestPaperModuleId());
            if(Objects.isNull(examTestPaperModules)){
                throw new BaseException("该计划不存在模板配置！");
            }
            long questionNum = 0;
            if (!CollectionUtils.isEmpty(examTestPaperModules.getExamTestPaperRequired())) {
                questionNum += examTestPaperModules.getExamTestPaperRequired().size();
            }
            if(!CollectionUtils.isEmpty(examTestPaperModules.getExamTestPaperExtractRuleList())){
                for (ExamTestPaperExtractRule rule : examTestPaperModules.getExamTestPaperExtractRuleList()) {
                    questionNum += rule.getNumber();
                }
            }
            List<ExamTestPaper> testPapers = new ArrayList<>();
            if (e.getExamType().equals(PlanTypeEnums.CYCLE.getCode())) {
                LocalDate date = LocalDate.now();
                if (date.isBefore(e.getExamStartTime().toLocalDate()) || date.isAfter(e.getExamEndTime().toLocalDate())) {
                    return;
                }
            }
            // 当发布的计划为固定计划时直接针对考试人员进行考卷的生成
            List<ExamPlanVenue> examPlanVenues = examPlanVenueService.selectExamPlanVenueByPlanId(e.getId());
            if(examPlanVenues.isEmpty()){
                throw new BaseException("计划未配置考场信息");
            }
            List<Long> userIds = new ArrayList<>();
            examPlanVenues.forEach(v->{
                if(CollectionUtils.isEmpty(v.getExamPlanVenueUserList())){
                    return;
                }
                userIds.addAll(v.getExamPlanVenueUserList().stream().map(ExamPlanVenueUser::getUserId).collect(Collectors.toList()));
            });
            List<SysUser> sysUsers = userService.selectUserByIds(userIds);
            Map<Long, SysUser> userMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity()));
            for (ExamPlanVenue examPlanVenue : examPlanVenues) {
                if(CollectionUtils.isEmpty(examPlanVenue.getExamPlanVenueUserList())){
                    throw new BaseException("存在考场未配置考试人员");
                }
                for (ExamPlanVenueUser u : examPlanVenue.getExamPlanVenueUserList()) {
                    SysUser sysUser = userMap.get(u.getUserId());
                    ExamTestPaper examTestPaper = new ExamTestPaper();
                    examTestPaper.setId(SnowflakeIdWorker.build().nextId());
                    examTestPaper.setExemPlanId(e.getId());
                    examTestPaper.setName(e.getName() + examPlanVenue.getExamPlace() + sysUser.getUserName());
                    examTestPaper.setTestPaperModuleId(e.getExamTestPaperModuleId());
                    examTestPaper.setUserId(u.getUserId());
                    examTestPaper.setDeptId(sysUser.getDeptId());
                    examTestPaper.setPostId(e.getPostId());
                    examTestPaper.setPostLevelCode(e.getPostLevelCode());
                    examTestPaper.setGrade(examTestPaperModules.getTotalGrade());
                    examTestPaper.setQuestionNum(questionNum);
                    if(Objects.isNull(SecurityContextHolder.getContext().getAuthentication())){
                        examTestPaper.setCreateBy("auto-by-server");
                    }else{
                        examTestPaper.setCreateBy(SecurityUtils.getUsername());

                    }
                    examTestPaper.setCreateTime(LocalDateTime.now());
                    examTestPaper.setIsDel(0L);
                    examTestPaper.setState(ExamTestPaperStateEnums.WAIT_RECEIVE.getCode());
                    testPapers.add(examTestPaper);
                }
            }
            examTestPaperService.batchInsertExamTestPaper(testPapers);
        });
    }

    @Override
    public List<ExamPlan> listByDate(LocalDate month) {
        // 获取某个月的考试场次信息
        List<ExamPlanVenue> venues = examPlanVenueService.selectExamPlanVenueDate(month);
        if(venues.isEmpty()){
            return Collections.emptyList();
        }
        return examPlanMapper.selectExamPlanByIds(venues.stream().map(ExamPlanVenue::getExamPlanId).toList());
    }

    @Override
    public int finish(Long exemPlanId) {
        return examPlanMapper.updateStatus(Arrays.asList(exemPlanId), PlanStatusEnums.FINISH.getCode());
    }

    @Override
    public List<Long> selectExamPlanOrderByCreateTime(Integer limitNum) {
        return examPlanMapper.selectExamPlanOrderByCreateTime(limitNum);
    }
}
